﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

#if !WINRT
using System.Windows;
using System.Windows.Threading;
#else

using Windows.UI.Xaml;
#endif

// From http://joshsmithonwpf.wordpress.com/2008/07/22/enable-elementname-bindings-with-elementspy/

namespace MishraReader
{
    /// <summary>
    ///   When placed into an element's Resources collection the spy's Element property returns that containing element. Use the NameScopeSource attached property to bridge an element's NameScope to other elements.
    /// </summary>
    public class ElementSpy : 
#if !WINRT
        Freezable
#else
        DependencyObject
#endif
    {
        public static readonly DependencyProperty
            NameScopeSourceProperty =
                DependencyProperty.RegisterAttached(
                    "NameScopeSource",
                    typeof(ElementSpy),
                    typeof(ElementSpy),
                    new UIPropertyMetadata(
                        null, OnNameScopeSourceChanged));

        private DependencyObject _element;

        public DependencyObject Element
        {
            get
            {
                if (_element == null)
                {
                    var prop = typeof(Freezable).GetProperty("InheritanceContext", BindingFlags.Instance | BindingFlags.NonPublic);

                    _element = prop.GetValue(this, null) as DependencyObject;

                    if (_element != null)
                        base.Freeze();
                }
                return _element;
            }
        }

#if !WINRT
        protected override Freezable CreateInstanceCore()
        {
            // We are required to override this abstract method.
            throw new NotSupportedException();
        }
#endif

        public static ElementSpy GetNameScopeSource(
            DependencyObject obj)
        {
            return (ElementSpy)obj.GetValue(NameScopeSourceProperty);
        }

        public static void SetNameScopeSource(
            DependencyObject obj, ElementSpy value)
        {
            obj.SetValue(NameScopeSourceProperty, value);
        }

        private static void OnNameScopeSourceChanged(
            DependencyObject depObj,
            DependencyPropertyChangedEventArgs e)
        {
            var spy = e.NewValue as ElementSpy;
            if (spy == null || spy.Element == null)
                return;

            var scope =
                NameScope.GetNameScope(spy.Element);
            if (scope == null)
                return;

            depObj.Dispatcher.BeginInvoke(
                DispatcherPriority.Normal,
                (Action)delegate { NameScope.SetNameScope(depObj, scope); });
        }
    }
}